package com.reggie.service.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.reggie.acl.dataobject.AddressBook;
import com.reggie.acl.mapper.AddressBookMapper;
import com.reggie.common.enums.ResponseCode;
import com.reggie.common.util.AssertUtils;
import com.reggie.service.model.request.AddressBookSaveRequest;
import com.reggie.service.model.request.AddressBookSetDefaultRequest;
import com.reggie.service.model.request.AddressBookUpdateRequest;
import com.reggie.service.service.AddressBookService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * <p>
 * 地址管理 服务实现类
 * </p>
 *
 * @author yth
 * @since 2023-02-04
 */
@Service
public class AddressBookServiceImpl implements AddressBookService {

    @Autowired
    private AddressBookMapper addressBookMapper;

    @Override
    public List<AddressBook> listByUserId(long userId) {
        LambdaQueryWrapper<AddressBook> wrapper = Wrappers.lambdaQuery(AddressBook.class)
                .eq(AddressBook::getUserId, userId)
                .orderByDesc(AddressBook::getIsDefault)
                .orderByDesc(AddressBook::getUpdateTime);
        return addressBookMapper.selectList(wrapper);
    }

    @Override
    public boolean save(AddressBookSaveRequest request) {
        long userId = request.getUserId();
        LambdaQueryWrapper<AddressBook> wrapper = Wrappers.lambdaQuery(AddressBook.class);
        wrapper.eq(AddressBook::getUserId, userId).
                eq(AddressBook::getIsDefault, 1);
        AddressBook one = addressBookMapper.selectOne(wrapper);
        // 用户添加的第一个地址默认作为默认地址，否则添加的地址作为非默认地址
        AddressBook addressBook = toEntity(request);
        boolean defaultFlag = one == null;
        addressBook.setIsDefault(defaultFlag);
        addressBookMapper.insert(addressBook);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setDefault(AddressBookSetDefaultRequest request) {
        validateAddressOwner(request.getAddressBookId(), request.getUserId());
        // 把用户的默认地址改为 非默认地址
        LambdaUpdateWrapper<AddressBook> wrapper = Wrappers.lambdaUpdate(AddressBook.class)
                .eq(AddressBook::getUserId, request.getUserId())
                .eq(AddressBook::getIsDefault, true)
                .set(AddressBook::getIsDefault, false);
        addressBookMapper.update(new AddressBook(), wrapper);
        // 设置新默认地址
        AddressBook defaultAddress = new AddressBook();
        defaultAddress.setId(request.getAddressBookId());
        defaultAddress.setIsDefault(true);
        addressBookMapper.updateById(defaultAddress);
    }

    private void validateAddressOwner(long addressBookId, long userId) {
        AddressBook addressBook = addressBookMapper.selectById(addressBookId);
        AssertUtils.nonNull(addressBook, ResponseCode.CLIENT_ERROR, "更新的地址不存在");
        AssertUtils.equals(addressBook.getUserId(), userId, ResponseCode.CLIENT_ERROR, "非法操作");
    }

    private void validateAddressOwner(List<Long> addressBookIds, long userId) {
        List<AddressBook> addressBooks = addressBookMapper.selectBatchIds(addressBookIds);
        AssertUtils.equals(addressBooks.size(), addressBookIds.size(), ResponseCode.CLIENT_ERROR, "操作的地址不存在");
        for (AddressBook addressBook : addressBooks) {
            AssertUtils.equals(addressBook.getUserId(), userId, ResponseCode.CLIENT_ERROR, "非法操作");
        }
    }

    @Override
    public Optional<AddressBook> getById(long id) {
        return Optional.ofNullable(addressBookMapper.selectById(id));
    }

    @Override
    public void update(AddressBookUpdateRequest request) {
        validateAddressOwner(request.getId(), request.getUserId());
        AddressBook addressBook = toEntity(request);
        addressBookMapper.updateById(addressBook);
    }

    @Override
    public void removeByIds(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return;
        }
        addressBookMapper.deleteBatchIds(ids);
    }

    @Override
    public Optional<AddressBook> getDefault(long userId) {
        LambdaQueryWrapper<AddressBook> wrapper = Wrappers.lambdaQuery(AddressBook.class)
                .eq(AddressBook::getUserId, userId)
                .eq(AddressBook::getIsDefault, 1);
        return Optional.ofNullable(addressBookMapper.selectOne(wrapper));
    }

    private AddressBook toEntity(AddressBookSaveRequest request) {
        final AddressBook addressBook = new AddressBook();
        addressBook.setUserId(request.getUserId());
        addressBook.setConsignee(request.getConsignee());
        addressBook.setSex(request.getSex());
        addressBook.setPhone(request.getPhone());
        addressBook.setProvinceCode(request.getProvinceCode());
        addressBook.setProvinceName(request.getProvinceName());
        addressBook.setCityCode(request.getCityCode());
        addressBook.setCityName(request.getCityName());
        addressBook.setDistrictCode(request.getDistrictCode());
        addressBook.setDistrictName(request.getDistrictName());
        addressBook.setDetail(request.getDetail());
        addressBook.setLabel(request.getLabel());
        addressBook.setIsDefault(request.getIsDefault());
        return addressBook;
    }

    private AddressBook toEntity(AddressBookUpdateRequest request) {
        final AddressBook addressBook = new AddressBook();
        addressBook.setId(request.getId());
        addressBook.setUserId(request.getUserId());
        addressBook.setConsignee(request.getConsignee());
        addressBook.setSex(request.getSex());
        addressBook.setPhone(request.getPhone());
        addressBook.setProvinceCode(request.getProvinceCode());
        addressBook.setProvinceName(request.getProvinceName());
        addressBook.setCityCode(request.getCityCode());
        addressBook.setCityName(request.getCityName());
        addressBook.setDistrictCode(request.getDistrictCode());
        addressBook.setDistrictName(request.getDistrictName());
        addressBook.setDetail(request.getDetail());
        addressBook.setLabel(request.getLabel());
        addressBook.setIsDefault(request.getIsDefault());
        return addressBook;
    }
}
